【原创】Android 耗电信息统计服务——BatteryStats源码分析(一)

Android 耗电信息统计服务——BatteryStats源码分析(一)

概述

Android 中关于耗电的统计一般是关于功耗分析的重要信息,Bettery-historian工具也是依托于解析BatteryStats 的dump 信息来提供界面直观分析,并且电池电量耗费的源头实在太多,基本Android 设备上任何一个活动都会引起电池电量的消耗,Android 在统计电量上也在不断完善,不断的在更新,具体化耗电详情。耗电名单在主要记录在BatterySipper里面,虽然在源码中他并没有集成在service 端,实在frameworks/base/core 下,但是谷歌开放sdk 中并没有公开电量统计的API 或者文档,但是并不代表没有,因为安全中心->省电优化→耗电排行 中就是通过app 能显示出耗电详情排行,所以我们将从这个入口开始分析Android 是如何记录设备电池的耗电详情信息的

BatteryStats服务架构设计

由于系统中形形色色,所有的活动都会耗电,所以BatteryStats服务也是相当的复杂,所以首先我们需要摸清楚该服务的架构设计,以此来切入分析,我们首先来看一下BatteryStats 电池电量统计服务的架构图:
这里写图片描述
从图中我们可以看出整个电池管理服务的大概架构是如何的。那么这里面的每个类所担当的角色是怎样的呢?
BatteryStats: 这是一个抽象类,在我看来也算是整个电池信息统计服务的架构核心类,这里面定义了很多内部类:
Timer (记录时间信息状态);
ControllerActivityCounter(统计无线电数据传输,接受,以及idle状态);
Counter(记录计数信息的状态。如Alarm,Wakelock 等统计计数);
LongCounter(针对长期持续的活动统计,如屏幕亮灭,插拔充电等);
UID(针对App Uid 统计信息):
Uid由于是统计app 的耗电量,所以其还定义内部类:Wakelock (统计应用申请Wakelock 的情况),Sensor(统计应用使用sensor的情况),Proc(统计应用进程的信息),Pkg(统计应用包的信息,内部类Serv(统计该包名下服务的信息));

BatteryStatsImpl :为整个电池信息统计服务的计算核心类,虽然该类是在frameworks/base 端(并非放在services 端),但是从分析该服务源码能看出来,BatteryStatsServices 虽然是system_server 中一个服务,但是实际上该服务只是一个空壳(后面即将讲到),所有的电池耗电信息相关计算都是在BatteryStatsImpl 中实现的,该类继承自BatteryStats,并且实现了BatteryStats 中定义的所有的抽象类以及计算方法。

BatteryStatsHelper : 是BatteryStatsImpl 计算的一个辅助类,主要是提供给应用(比如设置,安全中心,360等)来展示耗电信息,这里面的定义了软件类和硬件耗电信息的计算类***PowerCalculator,并且提供获取耗电信息列表方法getUsageList()

BatterySipper: 英文解释为:电池吸管,这个类的对象才是每个耗电的实体项统计,在安全中心中耗电排行中,每一个耗电项都是一个BatterySipper对象。

以上对BatteryStats 服务中各个相关的类以及其作用做了一个大致的解释,那么其服务是怎么统计的呢,我们继续来一步一步剖析源码

服务启动

BatteryStats 服务是在AMS 的构造函数中启动的

ActivityManagerService 构造函数中:

mBatteryStatsService = new BatteryStatsService(systemContext, systemDir, mHandler);
mBatteryStatsService.getActiveStatistics().readLocked();
mBatteryStatsService.scheduleWriteToDisk();
mOnBattery = DEBUG_POWER ? true
        : mBatteryStatsService.getActiveStatistics().getIsOnBattery();
mBatteryStatsService.getActiveStatistics().setCallback(this);

在AMS 构造函数中创建BatteryStatsService 的对象,并且开始读取统计文件里已经保存的统计信息。并且开始异步 的去记录信息,设置Callback

BatteryStatsService初始化:

BatteryStatsService(Context context, File systemDir, Handler handler) {
    // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through.
    mContext = context;
    mUserManagerUserInfoProvider = new BatteryStatsImpl.UserInfoProvider() {
        private UserManagerInternal umi;
        @Override
        public int[] getUserIds() {
            if (umi == null) {
                umi = LocalServices.getService(UserManagerInternal.class);
            }
            return (umi != null) ? umi.getUserIds() : null;
        }
    };
    mStats = new BatteryStatsImpl(systemDir, handler, this, mUserManagerUserInfoProvider);
    mWorker = new BatteryExternalStatsWorker(context, mStats);
    mStats.setExternalStatsSyncLocked(mWorker);
    mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
            com.android.internal.R.integer.config_radioScanningTimeout) * 1000L);  //设置RadioScanningTimeout 值(0 * 1000L)
    mStats.setPowerProfileLocked(new PowerProfile(context)); //设置PowerProfile(电池基本参数信息)。
}

    public void publish() {
        ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
    }

1.在构造函数中,使用BatteryExternalStatsWorker 内部统计集合来收集电池耗电信息了(8.1之前的是创建一个新的线程batterystats-sync用来记录电池电量信息) ,从AMS中传过来的mHandler(ActivityManager线程)给BatteryStatsImpl 用于记录wakelock,PowerChange,charging 等信息。设置外部硬件统计对象mWorker
2.在AMS 中onStart()函数中调用BatteryStatsService.publish() ,将batterystats 服务注册到system_server 进程中。可以看到在publish 中逻辑:3.将batterystats 服务添加到ServiceManager 中。


我们这里需要重点关注BatteryStatsImpl 的初始化,因为从以上分析来看虽然电量统计服务是system_server进程中的一个服务,但是其主要只是一个proxy 的作用,整体的计算工作还是交给BatteryStatsImpl 去做的,所以BatteryStatsImpl 才是整个耗电信息的计算核心类。

BatteryStatsImpl 构造函数

private BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
        PlatformIdleStateCallback cb,
        UserInfoProvider userInfoProvider) {
    init(clocks);

    if (systemDir != null) {
        mFile = new JournaledFile(new File(systemDir, "batterystats.bin"),
                new File(systemDir, "batterystats.bin.tmp"));
    } else {
        mFile = null;
    }
    mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin"));
    mDailyFile = new AtomicFile(new File(systemDir, "batterystats-daily.xml"));
    mHandler = new MyHandler(handler.getLooper());
    mStartCount++;
    mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
    mScreenDozeTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
........
    initDischarge();
    clearHistoryLocked();
    updateDailyDeadlineLocked();
    mPlatformIdleStateCallback = cb;
    mUserInfoProvider = userInfoProvider;
}

构造函数大概干了几件事:
1.传入的mClocks 为AMS 启动时候创建的SystemClock。
2. 在/data/system/ 下创建 batterystats.bin 文件和其备份文

  • 10
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值